import * as d3 from 'd3'
export class RadarChart {
  chart = {}
  data = []
  divId = ''
  radius = 100
  total = 6
  level = 4
  rangeMin = 0
  rangeMax = 100
  piece = 0
  polygons = {
    webs: [],
    webPoints: []
  }
  color = d3.scaleOrdinal(d3.schemeCategory10)
  constructor (divId) {
    this.divId = divId
  }

  draw () {
    this.initChart()
    this.initAxis()
    this.drawBasicRadar()
    this.drawRadarArea()
  }

  initChart () {
    this.chart.padding = {
      left: 20,
      right: 50,
      top: 20,
      bottom: 20
    }
    this.chart.divHeight = document.getElementById(this.divId).offsetHeight -
        this.chart.padding.top -
        this.chart.padding.bottom
    this.chart.divWidth = document.getElementById(this.divId).offsetWidth -
        this.chart.padding.left -
        this.chart.padding.right

    this.chart.svg = d3
      .select('#' + this.divId)
      .append('svg')
      .attr('width', this.chart.divWidth +
          this.chart.padding.left +
          this.chart.padding.right
      )
      .attr('height', this.chart.divHeight +
          this.chart.padding.top +
          this.chart.padding.bottom
      )
      .attr('class', 'svg_chart')
  }

  initAxis () {
    this.radius = Math.min(this.chart.divWidth, this.chart.divHeight) * 0.4
    this.piece = 2 * Math.PI / this.total
    for (let i = this.level; i > 0; i--) {
      let webs = ''
      let webPoints = []
      let r = this.radius / this.level * i
      for (let j = 0; j < this.total; ++j) {
        let x = r * Math.sin(j * this.piece)
        let y = r * Math.cos(j * this.piece)
        webs += x + ',' + y + ' '
        webPoints.push({
          x: x,
          y: y
        })
      }
      this.polygons.webs.push(webs)
      this.polygons.webPoints.push(webPoints)
    }
    let domain = this.getRange()

    this.chart.rScale = {}
    for (let key in domain) {
      this.chart.rScale[key] = d3.scaleLinear()
        .domain(domain[key])
        .range([this.radius * 0.1, this.radius])
    }
  }

  drawBasicRadar () {
    let spider = this.chart.svg.append('g')
      .attr('class', 'radar')
      .attr('transform', 'translate(' + this.chart.divWidth / 2 + ',' + this.chart.divHeight / 2 + ')')
    this.drawWebs(spider)
    this.drawAxis(spider)
    this.drawLabel(spider)
  }

  drawWebs (spider) {
    let webs = spider.append('g')
      .attr('class', 'webs')

    webs.selectAll('.web')
      .data(this.polygons.webs)
      .enter()
      .append('polygon')
      .attr('class', 'web')
      .attr('points', d => d)
      .style('fill', 'none')
      .style('stroke', 'gray')
      .style('stroke-dasharray', ('10, 5'))
  }

  drawAxis (spider) {
    let allAxis = spider.append('g')
      .attr('class', 'allAxis')

    allAxis.selectAll('.axis')
      .data(this.polygons.webPoints[0])
      .enter()
      .append('line')
      .attr('class', 'axis')
      .attr('x1', 0)
      .attr('y1', 0)
      .attr('x2', d => d.x)
      .attr('y2', d => d.y)
      .style('stroke', 'black')
      .style('stroke-width', 0.5)
      .style('opacity', 0.7)
      .style('stroke-dasharray', ('10 5'))
  }

  drawLabel (spider) {
    let keys = Object.keys(this.data[0])
    let labels = spider.append('g')
      .attr('class', 'labels')

    let textPositions = []
    let textRadius = this.radius + 18
    for (let i = 0; i < this.total; ++i) {
      let x = textRadius * Math.sin(i * this.piece)
      if (x < 2) {
        x -= 18
      }
      textPositions.push({
        x: x,
        y: textRadius * Math.cos(i * this.piece),
        name: keys[i]
      })
    }
    labels.selectAll('.label')
      .data(textPositions)
      .enter()
      .append('text')
      .attr('x', d => d.x)
      .attr('y', d => d.y)
      .text(d => d.name)
  }

  getRange () {
    let keys = Object.keys(this.data[0])
    let range = []
    let extents = {}
    for (let i = 0; i < keys.length; ++i) {
      range = []
      for (let j = 0; j < this.data.length; ++j) {
        range.push(this.data[j][keys[i]])
      }
      extents[keys[i]] = d3.extent(range)
    }
    return extents
  }

  computeData () {
    let areaDatas = []
    let keys = Object.keys(this.data[0])
    for (let i = 0; i < this.data.length; ++i) {
      let area = ''
      let areaPoints = []
      for (let j = 0; j < this.total; ++j) {
        let r = this.chart.rScale[keys[j]](this.data[i][keys[j]])
        let x = r * Math.sin(j * this.piece)
        let y = r * Math.cos(j * this.piece)
        area += x + ',' + y + ' '
        areaPoints.push({
          x: x,
          y: y
        })
      }
      areaDatas.push({
        polygon: area,
        points: areaPoints
      })
    }
    return areaDatas
  }

  drawRadarArea () {
    let areaDatas = this.computeData()
    let spider = this.chart.svg.select('.radar')
    let areas = spider.append('g')
      .attr('class', 'areas')

    let area = areas.selectAll('.area')
      .data(areaDatas)
      .enter()
      .append('g')
      .attr('class', 'area')

    area.append('polygon')
      .attr('points', d => d.polygon)
      .style('stroke', (_, i) => this.color(i))
      .style('fill', (_, i) => this.color(i))
      .style('opacity', 0.6)

    let points = area.append('g').attr('class', 'points')
      .style('fill', (_, i) => this.color(i))
      .style('stroke', (_, i) => this.color(i))

    points.selectAll('circle')
      .data(d => d.points)
      .enter()
      .append('circle')
      .attr('cx', d => d.x)
      .attr('cy', d => d.y)
      .attr('r', 5)
  }
}
